package com.ttg.web.utils;

import com.ttg.common.enums.TagUpdateFrequencyEnum;
import com.ttg.common.utils.DateTimeUtil;
import com.ttg.model.pojo.PeopleInfo;
import com.ttg.model.pojo.TblTagInfo;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

/**
 * Description： TODO
 * Author: chenyou
 * Date: 2025/10/27 11:41
 * Company: ttg
 * Copyright: Copyright (c) 2025
 */
public class NextUpdateTimeUtil {

    /**
     * 计算指定时间 + n天，往后推1周首次命中更新日期
     */
    public static LocalDateTime nextUpdateByWeek(LocalDateTime curr,int plusday,String updateDate){

        String[] days = updateDate.split(",");
        Map<Integer, LocalDateTime> map = DateTimeUtil.weekStarts(curr,plusday);
        LocalDateTime next = null;
        for(Map.Entry<Integer, LocalDateTime> entry : map.entrySet()){
            Integer weekDay = entry.getKey();
            boolean match = Arrays.stream(days).anyMatch(o -> o.equals(weekDay.toString()));
            if(match){
                next = entry.getValue();
                break;
            }
        }
        return next;
    }

    public static LocalDateTime nextUpdateByMonth(LocalDateTime curr,int plusday,String updateDate){
        String[] days = updateDate.split(",");
        LinkedHashMap<String, LocalDateTime> map = DateTimeUtil.monthStarts(curr,plusday);
        //替换末尾3天key
        List<LocalDate> lastDay3 = lastDay3(curr,plusday);
        int j = 1;
        for(int i=lastDay3.size()-1;i>=0;i--){
            String key = String.valueOf(lastDay3.get(i).getDayOfMonth());
            LocalDateTime obj = map.get(key);
            if(Objects.nonNull(obj)){
                insertBefore(map,key,"lastday"+j,obj);
                j++;
            }
        }

        LocalDateTime next = null;
        for(Map.Entry<String, LocalDateTime> entry : map.entrySet()){
            String key = entry.getKey();
            boolean match = Arrays.stream(days).anyMatch(o -> o.equals(key.toString()));
            if(match){
                next = entry.getValue();
                break;
            }
        }
        return next;
    }   

    public static List<LocalDate> lastDay3(LocalDateTime base, int plusday){
        // 1) 推后31天得到区间 [start, end]
        LocalDateTime start = base.plusDays(plusday); // 2025-10-31
        LocalDateTime end   = start.plusDays(30); // 2025-11-30

        // 2) 找到该区间内“月末的3天”
        Set<LocalDate> endOfMonths = new LinkedHashSet<>();
        LocalDate cur = start.toLocalDate();
        while (!cur.isAfter(end.toLocalDate())) {
            LocalDate eom = cur.with(TemporalAdjusters.lastDayOfMonth());
            // 若该月末落在区间内，则加入其“月末3天”
            if (!eom.isAfter(end.toLocalDate())) {
                endOfMonths.add(eom);
                endOfMonths.add(eom.minusDays(1));
                endOfMonths.add(eom.minusDays(2));
            }
            cur = cur.plusMonths(1);
        }

        // 3) 落在 [start, end] 内再筛选并输出
        List<LocalDate> hits = new ArrayList<>();
        for (LocalDate d : endOfMonths) {
            if (!d.isBefore(start.toLocalDate()) && !d.isAfter(end.toLocalDate())) {
                hits.add(d);
            }
        }
        hits.sort(Comparator.naturalOrder());
        return hits;
    }

    public static <K, V> boolean insertBefore(
            LinkedHashMap<K, V> map, K anchor, K newKey, V value) {
        Objects.requireNonNull(map);
        if (anchor == null || newKey == null) throw new NullPointerException();
        if (map.containsKey(newKey)) return false;

        Map<K, V> temp = new LinkedHashMap<>();
//        V v = map.remove(anchor);
//        if (v == null) return false; // anchor 不存在

        map.forEach((k, v2) -> {
            if (k.equals(anchor)){
                temp.put(newKey, value);
            }else {
                temp.put(k, v2);
            }

        });
        map.clear();
        map.putAll(temp);
        return true;
    }

    public static LocalDateTime firstUpdateTime(TblTagInfo tagInfo){
        LocalDateTime nextUpdateTime = null;
        String updateFrequency = tagInfo.getUpdateFrequency();
        String updateDateScope = tagInfo.getUpdateDateScope();
        String updateDate = tagInfo.getTagUpdateDates();
        LocalTime updateTime = tagInfo.getTagUpdateTime();
        TagUpdateFrequencyEnum frequencyEnum = TagUpdateFrequencyEnum.getByVal(updateFrequency);
        String time = DateTimeUtil.hh_mm_ssToStr(updateTime);
        int hour = Integer.parseInt(time.split(":")[0]);
        int minute = Integer.parseInt(time.split(":")[1]);
        int second = Integer.parseInt(time.split(":")[2]);
        LocalDateTime now = LocalDateTime.now();
        switch (frequencyEnum){
            case DAILY:

                nextUpdateTime = LocalDate.now().atTime(hour, minute,second);
                if(nextUpdateTime.isBefore(now)){
                    nextUpdateTime = now.toLocalDate().plusDays(1).atTime(hour, minute,second);
                }
                //具有时间范围，则需检查下次更新时间是否在有效期内
                if(!StringUtils.isEmpty(updateDateScope)){
                    LocalDateTime startDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[0] + "000000");
                    LocalDateTime endDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[1] + "235959");
                    //小于开始时间,设置下次更新时间为开始日期+time
                    if(nextUpdateTime.isBefore(startDate)){
                        nextUpdateTime = startDate.toLocalDate().atTime(hour, minute,second);
                    }
                    //大于结束时间,设置下次更新时间为2099-12-31 23:59:59
                    if(nextUpdateTime.isAfter(endDate)){
                        nextUpdateTime = LocalDateTime.of(2099,12,31,23,59,59);
                    }
                }
                break;
            case WEEKLY:
                nextUpdateTime = LocalDate.now().atTime(hour, minute,second);
                if(nextUpdateTime.isBefore(now)){
                    nextUpdateTime = NextUpdateTimeUtil.nextUpdateByWeek(now,1,updateDate);
                }else{
                    nextUpdateTime = NextUpdateTimeUtil.nextUpdateByWeek(now,0,updateDate);
                }
                nextUpdateTime = nextUpdateTime.toLocalDate().atTime(hour, minute,second);

                //具有时间范围，则需检查下次更新时间是否在有效期内
                if(!StringUtils.isEmpty(updateDateScope)){
                    LocalDateTime startDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[0] + "000000");
                    LocalDateTime endDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[1] + "235959");
                    //小于开始时间,设置下次更新时间为开始日期+time
                    if(nextUpdateTime.isBefore(startDate)){
                        nextUpdateTime = NextUpdateTimeUtil.nextUpdateByWeek(startDate,0,updateDate).toLocalDate().atTime(hour, minute,second);
                    }
                    //大于结束时间,设置下次更新时间为2099-12-31 23:59:59
                    if(nextUpdateTime.isAfter(endDate)){
                        nextUpdateTime = LocalDateTime.of(2099,12,31,23,59,59);
                    }
                }
                break;
            case MONTHLY:
                nextUpdateTime = LocalDate.now().atTime(hour, minute,second);
                if(nextUpdateTime.isBefore(now)){
                    nextUpdateTime = NextUpdateTimeUtil.nextUpdateByMonth(now,1,updateDate);
                }else{
                    nextUpdateTime = NextUpdateTimeUtil.nextUpdateByMonth(now,0,updateDate);
                }
                nextUpdateTime = nextUpdateTime.toLocalDate().atTime(hour, minute,second);
                //具有时间范围，则需检查下次更新时间是否在有效期内
                if(!StringUtils.isEmpty(updateDateScope)){
                    LocalDateTime startDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[0] + "000000");
                    LocalDateTime endDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[1] + "235959");
                    //小于开始时间,设置下次更新时间为开始日期+time
                    if(nextUpdateTime.isBefore(startDate)){
                        nextUpdateTime = NextUpdateTimeUtil.nextUpdateByMonth(startDate,0,updateDate).toLocalDate().atTime(hour, minute,second);
                    }
                    //大于结束时间,设置下次更新时间为2099-12-31 23:59:59
                    if(nextUpdateTime.isAfter(endDate)){
                        nextUpdateTime = LocalDateTime.of(2099,12,31,23,59,59);
                    }
                }
                break;
            default:

        }
        return nextUpdateTime;
    }

    public static LocalDateTime firstUpdateTime(PeopleInfo peopleInfo){
        LocalDateTime nextUpdateTime = null;
        String updateFrequency = peopleInfo.getUpdateFrequency();
        String updateDateScope = peopleInfo.getUpdateDateScope();
        String updateDate = peopleInfo.getPepUpdateDates();
        LocalTime updateTime = peopleInfo.getPepUpdateTime();
        TagUpdateFrequencyEnum frequencyEnum = TagUpdateFrequencyEnum.getByVal(updateFrequency);
        String time = DateTimeUtil.hh_mm_ssToStr(updateTime);
        int hour = Integer.parseInt(time.split(":")[0]);
        int minute = Integer.parseInt(time.split(":")[1]);
        int second = Integer.parseInt(time.split(":")[2]);
        LocalDateTime now = LocalDateTime.now();
        switch (frequencyEnum){
            case DAILY:

                nextUpdateTime = LocalDate.now().atTime(hour, minute,second);
                if(nextUpdateTime.isBefore(now)){
                    nextUpdateTime = now.toLocalDate().plusDays(1).atTime(hour, minute,second);
                }
                //具有时间范围，则需检查下次更新时间是否在有效期内
                if(!StringUtils.isEmpty(updateDateScope)){
                    LocalDateTime startDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[0] + "000000");
                    LocalDateTime endDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[1] + "235959");
                    //小于开始时间,设置下次更新时间为开始日期+time
                    if(nextUpdateTime.isBefore(startDate)){
                        nextUpdateTime = startDate.toLocalDate().atTime(hour, minute,second);
                    }
                    //大于结束时间,设置下次更新时间为2099-12-31 23:59:59
                    if(nextUpdateTime.isAfter(endDate)){
                        nextUpdateTime = LocalDateTime.of(2099,12,31,23,59,59);
                    }
                }
                break;
            case WEEKLY:
                nextUpdateTime = LocalDate.now().atTime(hour, minute,second);
                if(nextUpdateTime.isBefore(now)){
                    nextUpdateTime = NextUpdateTimeUtil.nextUpdateByWeek(now,1,updateDate);
                }else{
                    nextUpdateTime = NextUpdateTimeUtil.nextUpdateByWeek(now,0,updateDate);
                }
                nextUpdateTime = nextUpdateTime.toLocalDate().atTime(hour, minute,second);

                //具有时间范围，则需检查下次更新时间是否在有效期内
                if(!StringUtils.isEmpty(updateDateScope)){
                    LocalDateTime startDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[0] + "000000");
                    LocalDateTime endDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[1] + "235959");
                    //小于开始时间,设置下次更新时间为开始日期+time
                    if(nextUpdateTime.isBefore(startDate)){
                        nextUpdateTime = NextUpdateTimeUtil.nextUpdateByWeek(startDate,0,updateDate).toLocalDate().atTime(hour, minute,second);
                    }
                    //大于结束时间,设置下次更新时间为2099-12-31 23:59:59
                    if(nextUpdateTime.isAfter(endDate)){
                        nextUpdateTime = LocalDateTime.of(2099,12,31,23,59,59);
                    }
                }
                break;
            case MONTHLY:
                nextUpdateTime = LocalDate.now().atTime(hour, minute,second);
                if(nextUpdateTime.isBefore(now)){
                    nextUpdateTime = NextUpdateTimeUtil.nextUpdateByMonth(now,1,updateDate);
                }else{
                    nextUpdateTime = NextUpdateTimeUtil.nextUpdateByMonth(now,0,updateDate);
                }
                nextUpdateTime = nextUpdateTime.toLocalDate().atTime(hour, minute,second);
                //具有时间范围，则需检查下次更新时间是否在有效期内
                if(!StringUtils.isEmpty(updateDateScope)){
                    LocalDateTime startDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[0] + "000000");
                    LocalDateTime endDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[1] + "235959");
                    //小于开始时间,设置下次更新时间为开始日期+time
                    if(nextUpdateTime.isBefore(startDate)){
                        nextUpdateTime = NextUpdateTimeUtil.nextUpdateByMonth(startDate,0,updateDate).toLocalDate().atTime(hour, minute,second);
                    }
                    //大于结束时间,设置下次更新时间为2099-12-31 23:59:59
                    if(nextUpdateTime.isAfter(endDate)){
                        nextUpdateTime = LocalDateTime.of(2099,12,31,23,59,59);
                    }
                }
                break;
            default:

        }
        return nextUpdateTime;
    }
    public static LocalDateTime nextUpdateTime(TblTagInfo tagInfo){
        LocalDateTime nextUpdateTime = null;
        String updateFrequency = tagInfo.getUpdateFrequency();
        String updateDateScope = tagInfo.getUpdateDateScope();
        String updateDate = tagInfo.getTagUpdateDates();
        LocalTime updateTime = tagInfo.getTagUpdateTime();
        TagUpdateFrequencyEnum frequencyEnum = TagUpdateFrequencyEnum.getByVal(updateFrequency);
        LocalDateTime curr = tagInfo.getTagNextUpdateTime();
        String time = DateTimeUtil.hh_mm_ssToStr(updateTime);
        int hour = Integer.parseInt(time.split(":")[0]);
        int minute = Integer.parseInt(time.split(":")[1]);
        int second = Integer.parseInt(time.split(":")[2]);
        switch (frequencyEnum){
            case DAILY:
                nextUpdateTime = curr.toLocalDate().plusDays(1).atTime(hour, minute,second);
                //具有时间范围，则需检查下次更新时间是否在有效期内
                if(!StringUtils.isEmpty(updateDateScope)){
                    LocalDateTime startDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[0] + "000000");
                    LocalDateTime endDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[1] + "235959");
                    //小于开始时间,设置下次更新时间为开始日期+time
                    if(nextUpdateTime.isBefore(startDate)){
                        nextUpdateTime = startDate.toLocalDate().atTime(hour, minute,second);
                    }
                    //大于结束时间,设置下次更新时间为2099-12-31 23:59:59
                    if(nextUpdateTime.isAfter(endDate)){
                        nextUpdateTime = LocalDateTime.of(2099,12,31,23,59,59);
                    }
                }
                break;
            case WEEKLY:
                //计算本次更新时间往后推一周，首次命中的更新日期
                LocalDateTime next = NextUpdateTimeUtil.nextUpdateByWeek(curr,1,updateDate);

                nextUpdateTime = next.toLocalDate().plusDays(1).atTime(hour, minute,second);
                //具有时间范围，则需检查下次更新时间是否在有效期内
                if(!StringUtils.isEmpty(updateDateScope)){
                    LocalDateTime startDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[0] + "000000");
                    LocalDateTime endDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[1] + "235959");
                    //小于开始时间,设置下次更新时间为开始日期+time
                    if(nextUpdateTime.isBefore(startDate)){
                        nextUpdateTime = NextUpdateTimeUtil.nextUpdateByWeek(startDate,0,updateDate).toLocalDate().atTime(hour, minute,second);
                    }
                    //大于结束时间,设置下次更新时间为2099-12-31 23:59:59
                    if(nextUpdateTime.isAfter(endDate)){
                        nextUpdateTime = LocalDateTime.of(2099,12,31,23,59,59);
                    }
                }
                break;
            case MONTHLY:
                //计算倒数1，2，3天日期
                //计算本次更新时间往后推一周，首次命中的更新日期
                LocalDateTime next1 = NextUpdateTimeUtil.nextUpdateByMonth(curr,1,updateDate);
                nextUpdateTime = next1.toLocalDate().plusDays(1).atTime(hour, minute,second);
                //具有时间范围，则需检查下次更新时间是否在有效期内
                if(!StringUtils.isEmpty(updateDateScope)){
                    LocalDateTime startDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[0] + "000000");
                    LocalDateTime endDate = DateTimeUtil.strToYYYYMMDDHHMMSS(updateDateScope.split("-")[1] + "235959");
                    //小于开始时间,设置下次更新时间为开始日期+time
                    if(nextUpdateTime.isBefore(startDate)){
                        nextUpdateTime = NextUpdateTimeUtil.nextUpdateByMonth(startDate,0,updateDate).toLocalDate().atTime(hour, minute,second);
                    }
                    //大于结束时间,设置下次更新时间为2099-12-31 23:59:59
                    if(nextUpdateTime.isAfter(endDate)){
                        nextUpdateTime = LocalDateTime.of(2099,12,31,23,59,59);
                    }
                }
                break;
            default:

        }
        return nextUpdateTime;
    }


    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();
//        Map<Integer, LocalDateTime> m = weekStarts(now,1);
        LinkedHashMap<String, LocalDateTime> m1 = DateTimeUtil.monthStarts(now,1);
        m1.forEach((k, v) -> System.out.printf("%d=%s%n", k, v));
        lastDay3(now,1);

    }
}
